﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PerfAnalyzerLib
{
	public class CounterStats
	{
		private double _min;
		private double _max;
		private double _average;
		private double _standardDeviation;
		private double _percentile25th;
		private double _percentile50th;
		private double _percentile75th;
		private double _percentile90th;
		private double _percentile95th;
		private double _percentile99th;
		//public double Percentile999th;
		//public double Percentile9999th;
		// TODO Trend

		public double Min { get { return _min; } }
		public double Max { get { return _max; } }
		public double Average { get { return _average; } }
		public double StandardDeviation { get { return _standardDeviation; } }
		public double Percentile25th { get { return _percentile25th; } }
		public double Percentile50th { get { return _percentile50th; } }
		public double Percentile75th { get { return _percentile75th; } }
		public double Percentile90th { get { return _percentile90th; } }
		public double Percentile95th { get { return _percentile95th; } }
		public double Percentile99th { get { return _percentile99th; } }

		public CounterStats(double[] values)
		{
			CalculateStats(values);
		}

		private void CalculateStats(double[] values)
		{
			if (null == values)
			{
				throw new ArgumentNullException("Cannot calculate statistics, null array.");
			}

			if (0 == values.Length)
			{
				throw new ArgumentException("Cannot calculate statistics on a empty array.");
			}

			double[] sortedValues = new double[values.Length];
			Array.Copy(values, sortedValues, values.Length);
			Array.Sort(sortedValues);

			_min = sortedValues[0];
			_max = sortedValues[sortedValues.Length - 1];

			// Test for static counter
			if (_min == _max)
			{
				_average = _percentile25th = _percentile50th = _percentile75th = _percentile90th = _percentile95th = _percentile99th = _min;
				_standardDeviation = 0;
				return;
			}

			double sum = 0;
			double sumOfSquares = 0;	// for standard deviation
			foreach(double value in sortedValues)
			{
				sum += value;
				sumOfSquares += value * value;
			}

			// TODO faster with lambdas?
			_average = sum / sortedValues.Length;
			sumOfSquares = sumOfSquares / sortedValues.Length;
			_standardDeviation = Math.Sqrt(sumOfSquares - _average * _average);

			_percentile25th = sortedValues[(int)(sortedValues.Length * 0.25)];
			_percentile50th = sortedValues[(int)(sortedValues.Length * 0.50)];
			_percentile75th = sortedValues[(int)(sortedValues.Length * 0.75)];
			_percentile90th = sortedValues[(int)(sortedValues.Length * 0.90)];
			_percentile95th = sortedValues[(int)(sortedValues.Length * 0.95)];
			_percentile99th = sortedValues[(int)(sortedValues.Length * 0.99)];
		}
	}
}
